[XEN][POWERPC] Allocate more memory than RMA for Dom0
authorJimi Xenidis <jimix@watson.ibm.com>
Sun, 27 Aug 2006 20:12:00 +0000 (16:12 -0400)
committerJimi Xenidis <jimix@watson.ibm.com>
Sun, 27 Aug 2006 20:12:00 +0000 (16:12 -0400)
The following patch will only effect Dom0 at the moment and allow it
to be created with memory larger than RMA.  It works by allocating
extents (AKA chunks) of memory of an order specified by the processor.
The extent size should be a value that is capabable of mapping a
"large page" so we use the 970s large page size.  These extents are
tracked by an extents list that simply tracks these page allocations
and what there mapping is.  Other sub-systems effected by this:
  - Dom0 OFD devtree /memory cleanup
  - log_large_page_sizes is now an array
  - Config for minumum Dom0 size

Caveats:
 - There is a hack around HTAB allocation because we currently
   allocate one at domain creation time, this will be correct by a
   patch to follow.
 - Dom0, or domains capable of mapping mfns byt have their extents be
   PFN=MFN

Signed-off-by: Jimi Xenidis <jimix@watson.ibm.com>
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
13 files changed:
xen/arch/powerpc/Makefile
xen/arch/powerpc/domain.c
xen/arch/powerpc/domain_build.c
xen/arch/powerpc/memory.c
xen/arch/powerpc/mm.c
xen/arch/powerpc/ofd_fixup.c
xen/arch/powerpc/ofd_fixup_memory.c [new file with mode: 0644]
xen/arch/powerpc/oftree.h
xen/arch/powerpc/powerpc64/ppc970.c
xen/include/asm-powerpc/config.h
xen/include/asm-powerpc/domain.h
xen/include/asm-powerpc/mm.h
xen/include/asm-powerpc/processor.h

index c37a307f1c9b83be1180efe0ffecef8615a4f0bf..09c52bc0398fbbb5ad96680948d1dd40489a60e1 100644 (file)
@@ -31,6 +31,7 @@ obj-y += mpic_init.o
 obj-y += of-devtree.o
 obj-y += of-devwalk.o
 obj-y += ofd_fixup.o
+obj-y += ofd_fixup_memory.o
 obj-y += physdev.o
 obj-y += rtas.o
 obj-y += setup.o
index fb7a5ed95aa6b62dae53a0bdf7df5643a42d1af0..8cb2eb7acb81179d2a32f27088cf46f7edc32a7d 100644 (file)
@@ -114,6 +114,8 @@ int arch_domain_create(struct domain *d)
     }
     htab_alloc(d, htab_order_pages);
 
+    INIT_LIST_HEAD(&d->arch.extent_list);
+
     return 0;
 }
 
@@ -262,6 +264,7 @@ void sync_vcpu_execstate(struct vcpu *v)
 void domain_relinquish_resources(struct domain *d)
 {
     free_domheap_pages(d->arch.rma_page, d->arch.rma_order);
+    free_extents(d);
 }
 
 void arch_dump_domain_info(struct domain *d)
index 3f18a0f101d31405a39dc0bf1bdcfa9912b18d4e..3d5eefde735cd32b521921c46b1d9fae863fbc13 100644 (file)
@@ -30,6 +30,8 @@
 #include <asm/papr.h>
 #include "oftree.h"
 
+#define log2(x) ffz(~(x))
+
 extern int parseelfimage_32(struct domain_setup_info *dsi);
 extern int loadelfimage_32(struct domain_setup_info *dsi);
 
@@ -109,8 +111,10 @@ int construct_dom0(struct domain *d,
     struct domain_setup_info dsi;
     ulong dst;
     u64 *ofh_tree;
+    uint rma_nrpages = 1 << d->arch.rma_order;
     ulong rma_sz = rma_size(d->arch.rma_order);
     ulong rma = page_to_maddr(d->arch.rma_page);
+    uint htab_order;
     start_info_t *si;
     ulong eomem;
     int am64 = 1;
@@ -151,13 +155,36 @@ int construct_dom0(struct domain *d,
     /* By default DOM0 is allocated all available memory. */
     d->max_pages = ~0U;
 
+    /* default is the max(1/16th of memory, CONFIG_MIN_DOM0_PAGES) */
     if (dom0_nrpages == 0) {
-        dom0_nrpages = 1UL << d->arch.rma_order;
+        dom0_nrpages = total_pages >> 4;
+
+        if (dom0_nrpages < CONFIG_MIN_DOM0_PAGES)
+            dom0_nrpages = CONFIG_MIN_DOM0_PAGES;
     }
 
+    /* make sure we are at least as big as the RMA */
+    if (dom0_nrpages < rma_nrpages)
+        dom0_nrpages = rma_nrpages;
+    else
+        dom0_nrpages = allocate_extents(d, dom0_nrpages, rma_nrpages);
+
     d->tot_pages = dom0_nrpages;
     ASSERT(d->tot_pages > 0);
     
+    htab_order = log2(d->tot_pages) - 6;
+    if (d->arch.htab.order > 0) {
+        /* we incorrectly allocate this too early so lets adjust if
+         * necessary */
+        printk("WARNING: htab allocated to early\n");
+        if (d->arch.htab.order < htab_order) {
+            printk("WARNING: htab reallocated for more memory: 0x%x\n",
+                htab_order);
+            htab_free(d);
+            htab_alloc(d, htab_order);
+        }
+    }
+
     ASSERT( image_len < rma_sz );
 
     si = (start_info_t *)(rma_addr(&d->arch, RMA_START_INFO) + rma);
@@ -276,7 +303,7 @@ int construct_dom0(struct domain *d,
 
     printk("DOM: pc = 0x%lx, r2 = 0x%lx\n", pc, r2);
 
-    ofd_dom0_fixup(d, *ofh_tree + rma, si, dst - rma);
+    ofd_dom0_fixup(d, *ofh_tree + rma, si);
 
     set_bit(_VCPUF_initialised, &v->vcpu_flags);
 
index 9c5c55f686977c189a49728784e1c3fc64b23d06..0e7a20af84a90600d03086dcc21888fabcacd9ab 100644 (file)
@@ -64,8 +64,7 @@ static void set_max_page(struct membuf *mb, uint entries)
     }
 }
 
-/* mark all memory from modules onward as unused, skipping hole(s),
- * and returning size of hole(s) */
+/* mark all memory from modules onward as unused */
 static void heap_init(struct membuf *mb, uint entries)
 {
     int i;
index 56c6c045dadd347c5949c0cf7c3e99fda222b5d9..1ca8f9fda414d1eb138eb9eef19256007b404e9c 100644 (file)
@@ -239,6 +239,69 @@ static int mfn_in_hole(ulong mfn)
     return 0;
 }
 
+static uint add_extent(struct domain *d, struct page_info *pg, uint order)
+{
+    struct page_extents *pe;
+
+    pe = xmalloc(struct page_extents);
+    if (pe == NULL)
+        return 0;
+
+    pe->pg = pg;
+    pe->order = order;
+    pe->pfn = page_to_mfn(pg);
+
+    list_add_tail(&pe->pe_list, &d->arch.extent_list);
+
+    return pe->pfn;
+}
+
+void free_extents(struct domain *d)
+{
+    /* we just need to free the memory behind list */
+    struct list_head *list;
+    struct list_head *ent;
+    struct list_head *next;
+
+    list = &d->arch.extent_list;
+    ent = list->next;
+
+    while (ent != list) {
+        next = ent->next;
+        xfree(ent);
+        ent = next;
+    }
+}
+
+uint allocate_extents(struct domain *d, uint nrpages, uint rma_nrpages)
+{
+    uint ext_order;
+    uint ext_nrpages;
+    uint total_nrpages;
+    struct page_info *pg;
+
+    ext_order = cpu_extent_order();
+    ext_nrpages = 1 << ext_order;
+
+    total_nrpages = rma_nrpages;
+
+    /* We only allocate in nr_extsz chunks so if you are not divisible
+     * you get more than you asked for */
+    while (total_nrpages < nrpages) {
+        pg = alloc_domheap_pages(d, ext_order, 0);
+        if (pg == NULL)
+            return total_nrpages;
+
+        if (add_extent(d, pg, ext_order) == 0) {
+            free_domheap_pages(pg, ext_order);
+            return total_nrpages;
+        }
+        total_nrpages += ext_nrpages;
+    }
+
+    return total_nrpages;
+}
+        
 int allocate_rma(struct domain *d, unsigned int order_pages)
 {
     ulong rma_base;
@@ -266,6 +329,7 @@ ulong pfn2mfn(struct domain *d, long pfn, int *type)
 {
     ulong rma_base_mfn = page_to_mfn(d->arch.rma_page);
     ulong rma_size_mfn = 1UL << d->arch.rma_order;
+    struct page_extents *pe;
 
     if (pfn < rma_size_mfn) {
         if (type)
@@ -280,6 +344,17 @@ ulong pfn2mfn(struct domain *d, long pfn, int *type)
         return pfn;
     }
 
+    /* quick tests first */
+    list_for_each_entry (pe, &d->arch.extent_list, pe_list) {
+        uint end_pfn = pe->pfn + (1 << pe->order);
+
+        if (pfn >= pe->pfn && pfn < end_pfn) {
+            if (type)
+                *type = PFN_TYPE_LOGICAL;
+            return page_to_mfn(pe->pg) + (pfn - pe->pfn);
+        }
+    }
+
     /* This hack allows dom0 to map all memory, necessary to
      * initialize domU state. */
     if (test_bit(_DOMF_privileged, &d->domain_flags)) {
index e23c2ccd9f7ec14955d406cad0c4ce57b278994b..e20978d9b138135e714f4389a464b44a3158e2f5 100644 (file)
@@ -13,7 +13,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *
- * Copyright (C) IBM Corp. 2005
+ * Copyright (C) IBM Corp. 2005, 2006
  *
  * Authors: Jimi Xenidis <jimix@watson.ibm.com>
  */
@@ -317,91 +317,6 @@ static ofdn_t ofd_rtas_props(void *m)
 }
 #endif
 
-struct mem_reg {
-    u64 addr;
-    u64 sz;
-};
-
-static ofdn_t ofd_memory_chunk_create(void *m, ofdn_t p,
-        const char *ppath,
-        const char *name,
-        const char *dt,
-        ulong start, ulong size)
-{
-    struct mem_reg reg;
-    char path[128];
-    ulong l;
-    u32 v;
-    ofdn_t n;
-    ulong nl = strlen(name) + 1;
-    ulong dtl = strlen(dt) + 1;
-
-    l = snprintf(path, sizeof (path), "%s/%s@%lx", ppath, name, start);
-    n = ofd_node_add(m, p, path, l + 1);
-    ofd_prop_add(m, n, "name", name, nl);
-
-    v = 1;
-    ofd_prop_add(m, n, "#address-cells", &v, sizeof (v));
-    v = 0;
-    ofd_prop_add(m, n, "#size-cells", &v, sizeof (v));
-
-    ofd_prop_add(m, n, "device_type", dt, dtl);
-
-    /* physical addresses usable without regard to OF */
-    reg.addr = start;
-    reg.sz = size;
-    ofd_prop_add(m, n, "reg", &reg, sizeof (reg));
-
-    return n;
-}
-
-static ofdn_t ofd_memory_props(void *m, struct domain *d, ulong eoload)
-{
-    ofdn_t n = -1;
-    ulong start = 0;
-    static char name[] = "memory";
-    ulong mem_size = rma_size(d->arch.rma_order);
-    ulong chunk_size = rma_size(d->arch.rma_order);
-
-    /* Remove all old memory props */
-    do {
-        ofdn_t old;
-
-        old = ofd_node_find_by_prop(m, OFD_ROOT, "device_type",
-                                    name, sizeof(name));
-        if (old <= 0) break;
-
-        ofd_node_prune(m, old);
-    } while (1);
-
-    while (start < mem_size) {
-        ulong size = (mem_size < chunk_size) ? mem_size : chunk_size;
-
-        n = ofd_memory_chunk_create(m, OFD_ROOT, "", "memory", "memory",
-                start, size);
-
-        if (start == 0) {
-            /* We are processing the first and RMA chunk */
-
-            /* free list of physical addresses available after OF and
-             * client program have been accounted for */
-            struct mem_reg avail[] = {
-                /* 0 til OF @ 32MiB - 16KiB stack */
-                { .addr = 0, .sz = ((32 << 20) - (16 << 10)) },
-                /* end of loaded material to the end the chunk - 1 page */
-                { .addr = eoload, .sz = chunk_size - eoload - PAGE_SIZE },
-                /* the last page is reserved for xen_start_info */
-            };
-            ofd_prop_add(m, n, "available", &avail,
-                    sizeof (avail));
-        }
-
-        start += size;
-        mem_size -= size;
-    }
-    return n;
-}
-
 static ofdn_t ofd_xen_props(void *m, struct domain *d, start_info_t *si)
 {
     ofdn_t n;
@@ -442,7 +357,7 @@ static ofdn_t ofd_xen_props(void *m, struct domain *d, start_info_t *si)
     return n;
 }
 
-int ofd_dom0_fixup(struct domain *d, ulong mem, start_info_t *si, ulong eoload)
+int ofd_dom0_fixup(struct domain *d, ulong mem, start_info_t *si)
 {
     void *m;
     const ofdn_t n = OFD_ROOT;
@@ -470,8 +385,8 @@ int ofd_dom0_fixup(struct domain *d, ulong mem, start_info_t *si, ulong eoload)
     printk("Add /chosen props\n");
     ofd_chosen_props(m, (char *)si->cmd_line);
 
-    printk("fix /memory@0 props\n");
-    ofd_memory_props(m, d, eoload);
+    printk("fix /memory props\n");
+    ofd_memory_props(m, d);
 
     printk("fix /xen props\n");
     ofd_xen_props(m, d, si);
diff --git a/xen/arch/powerpc/ofd_fixup_memory.c b/xen/arch/powerpc/ofd_fixup_memory.c
new file mode 100644 (file)
index 0000000..6582938
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright (C) IBM Corp. 2006
+ *
+ * Authors: Jimi Xenidis <jimix@watson.ibm.com>
+ */
+
+#include <xen/config.h>
+#include <xen/lib.h>
+#include <xen/sched.h>
+#include <public/xen.h>
+#include "of-devtree.h"
+#include "oftree.h"
+
+static char memory[] = "memory";
+
+struct mem_reg {
+    u64 addr;
+    u64 sz;
+};
+
+static void ofd_memory_clean(void *m)
+{
+    ofdn_t old;
+
+    /* Remove all old memory props */
+    do {
+        old = ofd_node_find_by_prop(m, OFD_ROOT, "device_type",
+                                    memory, sizeof(memory));
+        if (old <= 0)
+            break;
+
+        ofd_node_prune(m, old);
+    } while (1);
+}
+
+static ofdn_t ofd_memory_node_create(
+    void *m, ofdn_t p, const char *ppath, const char *name,
+    const char *dt, ulong start, ulong size)
+{
+    struct mem_reg reg;
+    char path[128];
+    ulong l;
+    ofdn_t n;
+    ulong nl = strlen(name) + 1;
+    ulong dtl = strlen(dt) + 1;
+
+    l = snprintf(path, sizeof (path), "%s/%s@%lx", ppath, name, start);
+    n = ofd_node_add(m, p, path, l + 1);
+    ofd_prop_add(m, n, "name", name, nl);
+    ofd_prop_add(m, n, "device_type", dt, dtl);
+
+    /* physical addresses usable without regard to OF */
+    reg.addr = start;
+    reg.sz = size;
+    ofd_prop_add(m, n, "reg", &reg, sizeof (reg));
+
+    return n;
+}
+
+static void ofd_memory_rma_node(void *m, struct domain *d)
+{
+    ulong size = rma_size(d->arch.rma_order);
+    ofdn_t n;
+
+    n = ofd_memory_node_create(m, OFD_ROOT, "", memory, memory, 0, size);
+    BUG_ON(n <= 0);
+}
+
+static void ofd_memory_extent_nodes(void *m, struct domain *d)
+{
+    ulong start;
+    ulong size;
+    ofdn_t n;
+    struct page_extents *pe;
+
+    list_for_each_entry (pe, &d->arch.extent_list, pe_list) {
+
+        start = pe->pfn << PAGE_SHIFT;
+        size = 1UL << (pe->order + PAGE_SHIFT);
+
+        n = ofd_memory_node_create(m, OFD_ROOT, "", memory, memory,
+                                    start, size);
+
+        BUG_ON(n <= 0);
+    }
+}
+
+void ofd_memory_props(void *m, struct domain *d)
+{
+    ofd_memory_clean(m);
+    ofd_memory_rma_node(m, d);
+    ofd_memory_extent_nodes(m,d);
+}
index bf1f210665b78b53816e04e9257f207317372555..f828e96c1a1c9a3d66e11a93b4e7d0a808f66016 100644 (file)
@@ -26,8 +26,8 @@ extern ulong oftree;
 extern ulong oftree_len;
 extern ulong oftree_end;
 
-extern int ofd_dom0_fixup(
-    struct domain *d, ulong mem, start_info_t *si, ulong dst);
+extern int ofd_dom0_fixup(struct domain *d, ulong mem, start_info_t *si);
+extern void ofd_memory_props(void *m, struct domain *d);
 
 extern int firmware_image_start[0];
 extern int firmware_image_size[0];
index 70979df9878ac185cfae019a46936ec86acb1693..9c9d5c2b82cbce0fcf738d731609e9b59814c459 100644 (file)
@@ -49,6 +49,10 @@ static struct rma_settings rma_orders[] = {
     { .order = 38, .rmlr0 = 0, .rmlr12 = 0, }, /* 256 GB */
 };
 
+static uint log_large_page_sizes[] = {
+    4 + 20, /* (1 << 4) == 16M */
+};
+
 static struct rma_settings *cpu_find_rma(unsigned int order)
 {
     int i;
@@ -66,14 +70,20 @@ unsigned int cpu_default_rma_order_pages(void)
 
 unsigned int cpu_large_page_orders(uint *sizes, uint max)
 {
-    uint lp_log_size = 4 + 20; /* (1 << 4) == 16M */
-    if (max < 1)
-        return 0;
+    uint i = 0;
 
-    sizes[0] = lp_log_size - PAGE_SHIFT;
+    while (i < max && i < ARRAY_SIZE(log_large_page_sizes)) {
+        sizes[i] = log_large_page_sizes[i] - PAGE_SHIFT;
+        ++i;
+    }
 
-    return 1;
-}    
+    return i;
+}
+
+unsigned int cpu_extent_order(void)
+{
+    return log_large_page_sizes[0] - PAGE_SHIFT;
+}
 
 void cpu_initialize(int cpuid)
 {
index 1c081a90ff0911791531288a6197c04a9aa42be8..bfa59ed3e546c86cf56c76b948ec0e9e50a82d86 100644 (file)
@@ -47,6 +47,8 @@ extern char __bss_start[];
 /* this should be per processor, but for now */
 #define CACHE_LINE_SIZE 128
 
+/* 256M - 64M of Xen space seems like a nice number */
+#define CONFIG_MIN_DOM0_PAGES (192 << (20 - PAGE_SHIFT))
 #define CONFIG_SHADOW 1
 #define CONFIG_GDB 1
 #define CONFIG_SMP 1
index 2d95c6a84baeb7428020f20bab5113630572326f..6f21f6d5fe50785ed898558d61f7608bbb069474 100644 (file)
@@ -38,6 +38,9 @@ struct arch_domain {
     struct page_info *rma_page;
     uint rma_order;
 
+    /* list of extents beyond RMA */
+    struct list_head extent_list;
+
     /* I/O-port access bitmap mask. */
     u8 *iobmp_mask;       /* Address of IO bitmap mask, or NULL.      */
 
index fd2f0111f0432a14ab01c88a030e9e7f06e43895..a3eeecf542d4ad14b5e7689c958d4efc9c3d0b84 100644 (file)
@@ -259,6 +259,8 @@ static inline unsigned long gmfn_to_mfn(struct domain *d, unsigned long gmfn)
 #define mfn_to_gmfn(_d, mfn) (mfn)
 
 extern int allocate_rma(struct domain *d, unsigned int order_pages);
+extern uint allocate_extents(struct domain *d, uint nrpages, uint rma_nrpages);
+extern void free_extents(struct domain *d);
 
 extern int steal_page(struct domain *d, struct page_info *page,
                         unsigned int memflags);
index 1c0d36d8ce076c2dc36eb6545b276c53dd89877c..dbecadbdab217e96d9d72389da5c88e1773efc8e 100644 (file)
@@ -40,6 +40,7 @@ struct cpu_user_regs;
 extern void show_registers(struct cpu_user_regs *);
 extern void show_execution_state(struct cpu_user_regs *);
 extern void show_backtrace(ulong sp, ulong lr, ulong pc);
+extern unsigned int cpu_extent_order(void);
 extern unsigned int cpu_default_rma_order_pages(void);
 extern uint cpu_large_page_orders(uint *sizes, uint max);
 extern void cpu_initialize(int cpuid);